#!/usr/bin/env python
# coding=utf-8

if __name__ == '__main__':
    """ for file debug"""
    import sys,os
    sys.path.insert(0,os.path.join( os.getcwd(), '..' ))

__author__ = 'vavava'


import threading,time
from queue import Queue
from vavava.base import LogAdapter
from vavava.basethread import BaseThread

class work(object):
    """
    base class for user-work-item,self.do() must be written over
    """
    def __init__(self,log=None):
        self.func=None
        self.log = LogAdapter(log)

    def do(self):
        self.log.error("Function building (work) ....")
        raise Exception("Function building ....")

    def timeout_routine(self):
        pass  #invoke by timeout-support-WorkQueue, after timeout happen

class WorkQueue(BaseThread):
    def __init__(self,type=0,maxsize=100,name="<unknown>",log=None):
        """
        type = 0: simple work queue
             = 1: work queue with timeout property
        IsWorking/paused/
        """
        BaseThread.__init__(self,name,log)
        self.t=type
        self.maxsize=maxsize
        self.works=Queue(maxsize)
        self._mutex=threading.RLock()
        self.last_working_time=None

    def run(self):
        if self.t == 0:
            self._do0()
        elif self.t == 1:
            self._do1()

    def _do0(self):
    # work without timeout support
        while self.IsRunning:
            try:
                if not self.works.empty() and not self.IsPaused:
                    work = self.works.get(block=True,timeout=0.5)
                    if __debug__ : self.log.debug("working %s"%self.getName())
                    work.do() # working ...
                else:
                    #if __debug__ and self.IsPaused: self.log.debug("paused")
                    #if __debug__ : self.log.debug("waiting %s"%self.getName())
                    time.sleep(0.5)
            except Exception as e:
                self.log.exception(e)
        if __debug__ : self.log.debug("stopped %s"%self.getName())

    def _do1(self):
        # work with timeout support
        while self.IsRunning:
            try:
                if not self.works.empty() and not self.IsPaused:
                    work = self.works.get(block=True,timeout=30.0)
                    self._mutex.acquire()
                    self.last_working_time = time.localtime(time.time())
                    self._mutex.release()
                    if __debug__ : self.log.debug("working %s"%self.getName())
                    work.do() # working ...
                    self._mutex.acquire()
                    self.last_working_time = None
                    self._mutex.release()
                else:
                    #if __debug__ and self.IsPaused: self.log.debug("paused")
                    #if __debug__ : self.log.debug("waiting %s"%self.getName())
                    time.sleep(0.5)
            except Exception as e:
                self.log.exception(e)
        if __debug__ : self.log.debug("stopped %s"%self.getName())

    def wq_start(self):
        self.running_start()

    def wq_pause(self,timeout=10.0):
        self.running_pause()

    def wq_resume(self):
        self.running_resume()

    def wq_stop(self,timeout=10.0,flush=True):
        self.log.debug("Stopped queue.")
        self.running_stop()
        self.join(timeout)
        if self.is_alive():
            self.log.warn("thread is not stop!!!![timeout]")
        if flush:
            self._flush_works()
        self.log.debug("Stopped with %d work in queue. (flush=%d)"%
                       (self.works.qsize(),flush))

    def QueueWork(self,work):
        if not self.IsRunning or not self.is_alive:
            self.log.debug("Queue stopped when new work come.")
            return
        try:
            self.works.put(item=work,block=False)
        except:
            self.log.error("work queue is full")
            raise

    def _flush_works(self):
        self.log.debug("Flush workqueue (%d)."%self.works.qsize())
        self.works.task_done()

    def __del__(self):
        self._stop()

    @property
    def IsWorking(self):
        # running and has work to do means "working"
        return self.is_alive and self.IsRunning and not self.works.empty()

    @property
    def QueueInfo(self):
        self._mutex.acquire()
        info = {
            "Ident":self._ident,
            "name":self.getName(),
            "InQueueSize":self.works.qsize(),
            "lastWorkingTime":self.last_working_time
        }
        self._mutex.release()
        return info

class MyWork(work):
    def __init__(self,seq=0,log=None):
        work.__init__(self, log)
        self.seq=seq

    def do(self):
        import time
        print("Hello DB !!!!!!! %d"%self.seq)
        time.sleep(1)
        print("CU DB !!!!!!! %d"%self.seq)

def main():
    workingLine=WorkQueue(type=0)
    workingLine.wq_start()
    try:
        seq=0
        while seq < 10:
            import time
            seq += 1
            print("Add a work : %d"%seq)
            workingLine.QueueWork(MyWork(seq))
            #time.sleep(1)
        time.sleep(3)
        workingLine.wq_pause()  # restart .........
        print('main thread(%f):paused'%time.clock())
        time.sleep(5)
        workingLine.wq_resume()  # restart .........
        print('main thread(%f):resumed'%time.clock())
        seq=0
        while seq < 100:
            import time
            seq += 1
            print("Add a work : %d"%seq)
            workingLine.QueueWork(MyWork(seq))
            time.sleep(1)

    except(KeyboardInterrupt):
        print('main thread(%f):stop'%time.clock())
        workingLine.wq_stop(timeout=5,flush=True)
        print('main thread(%f):stopped'%time.clock())

if __name__ == '__main__':
    main()



